
package com.devioustoast.turretdroid;

import java.util.concurrent.BlockingDeque;

import android.util.Log;

abstract class CameraConsumer implements Runnable {

  private static final String LOG_TAG = CameraConsumer.class.getSimpleName();
  private BlockingDeque<byte[]> mPictureRoll;
  private float mMaxImageVaraiance = 0.1f;
  private boolean mRun = true;

  public CameraConsumer(BlockingDeque<byte[]> pictureRoll) {
    mPictureRoll = pictureRoll;
  }
  
  public abstract void callback();

  public void run() {
    mRun = true;
    while (mRun) {
      if (isMovementDetected()) {
        callback();
      }
      try {
        Thread.sleep(500);
      } catch (InterruptedException e) {
        Log.w(LOG_TAG, e);
      }
    }
  }

  public void stop() {
    mRun = false;
  }
  
  public void setMaxImageVariance(float variance) {
    mMaxImageVaraiance = variance;
  }

  private boolean isMovementDetected() {
    while (mPictureRoll.size() > 2) {
      Log.d(LOG_TAG, String.format(
          "More than 2 pictures on the role found (%s).  Removing the " +
          "oldest pictures.", mPictureRoll.size()));
      try {
        mPictureRoll.take();
      } catch (InterruptedException e) {
        Log.w(LOG_TAG, e);
      }
    }
    if (mPictureRoll.size() == 2) {
      byte[] shorter = {};
      try {
        shorter = mPictureRoll.take();
      } catch (InterruptedException e) {
        Log.w(LOG_TAG, e);
      }
      byte[] longer = {};
      try {
        longer = mPictureRoll.take();
      } catch (InterruptedException e) {
        Log.w(LOG_TAG, e);
      }

      // If the array lengths are too different, then the pictures are
      // probably different.
      if (longer.length < shorter.length) {
        byte[] temp = shorter;
        shorter = longer;
        longer = temp;
      }
      float arrayLengthVariance = 1.0f - (float) shorter.length / longer.length;
      if (arrayLengthVariance >= mMaxImageVaraiance) {
        Log.d(LOG_TAG, String.format(
            "The array lengths varied too much: %s", arrayLengthVariance));
        return true;
      } else {
        Log.d(LOG_TAG, String.format(
            "Array lengths: %s %s; variance: %s",
            shorter.length, longer.length, arrayLengthVariance));
      }

      // XOR each byte of the pictures.  If more than MAX_IMAGE_VARIANCE of the
      // byte array is different, then the pictures are different.
      int numBytesDiffered = 0;
      for (int i = 0 ; i < shorter.length; i++) {
        if ((byte) (shorter[i] ^ longer[i]) != 0) {
          numBytesDiffered++;
        }
      }
      float byteVariance = 1.0f - ((float) numBytesDiffered / shorter.length);
      if (byteVariance >= mMaxImageVaraiance) {
        Log.d(LOG_TAG, String.format(
            "Pictures differred by more than %s%%: %s",
            mMaxImageVaraiance * 100, byteVariance));
        return true;
      } else {
        Log.d(LOG_TAG, String.format(
            "Pictures did NOT differ by more than %s%%: %s",
            mMaxImageVaraiance * 100, byteVariance));
      }
    }
    return false;
  }
}
